(* Class Options *)
class document = 
object
  val mutable t ="" (* Path to image*)
  val mutable l_c = [(0,0,0)] (* List of new colors *)
  val mutable c = [(0,0,0)] (* List of colors *)
  val mutable q = [(0,0,0,0)] (* List of colors & height *)
  
  method get_t = t
  method set_t n_t = t <- n_t
    
  method get_l_c = l_c
  method set_l_c n_l_c = l_c <- n_l_c
    
  method get_c = c
  method set_c n_c = c <- n_c
    
  method get_q = q
  method set_q n_q = q <- n_q
end

let d = new document

 

let set_file_image file_sel () = 
  d#set_t file_sel#filename;
  file_sel#destroy(); ()
let show_file_image () =
  let file_sel = GWindow.file_selection 
    ~title:"CardinoGen - Select an image"
    ~position:`CENTER_ON_PARENT
    ~filename:""
    ~border_width:10 () in
  ignore (file_sel#cancel_button#connect#clicked ~callback:file_sel#destroy);
  ignore(file_sel#ok_button#connect#clicked ~callback:(set_file_image file_sel));
  file_sel#show ();
 ()


let load_image = GMisc.image
  ~file:"./img/cardinogen.png" ()

let show_about () =
    let about = GWindow.about_dialog
      ~name:"CardinoGen"
      ~logo:load_image#pixbuf
      ~authors:["Cheron Augustin"; "Cloute Julien"; "Ly Franck"; "Pouzols Pierre"]
      ~website:"http://aeterman.fr/cardinogen"
      ~comments:"A 3D Mapping software."
      ~position:`CENTER_ON_PARENT
      ~destroy_with_parent:true () in
    about#show ();
    let _ =  about#connect#close ~callback:(fun () -> about#destroy ()) in
()

let spin = ref []

let spin_rec s = spin := s
    
(* Main window *)
let window = GWindow.window
  ~width:1024
  ~height:768
  ~resizable:true
  ~position:`CENTER
  ~title:"Cardinogen" ()
  
let vbox = GPack.vbox
  ~spacing:10
  ~border_width:10
  ~packing:window#add ()
            
let menubar = GMenu.menu_bar 
  ~packing:vbox#pack ()
  
(* Graphic Interface User *)
  
  
let factory = new GMenu.factory menubar
let file_menu = factory#add_submenu "File"
let pref_menu = factory#add_submenu "Preference"
let help_menu = factory#add_submenu "Help"
let abou_menu = factory#add_submenu "About" 
  
(* File menu *)
let factory = new GMenu.factory file_menu
let sub_menu = factory#add_item "Open" ~callback:show_file_image
let sub_menu = factory#add_item "Save as"
let sub_menu = factory#add_item "Quit" ~callback:window#destroy
  

(* Preference menu *)
let factory = new GMenu.factory pref_menu
let sub_menu = factory#add_item "Load Profile"
  
(* Help menu *)
(* Under construction *)
  
  
(* About menu *)
let factory = new GMenu.factory abou_menu
let sub_menu = factory#add_item "Us"
let sub_menu = factory#add_item "Cardinogen" ~callback:show_about
  
  
(* Notebook menu *)
let notebook = GPack.notebook ~packing:vbox#add ()
  
  
(* Note Load *)
let load_nb = 
  GBin.scrolled_window
    ~vpolicy:`AUTOMATIC
    ~hpolicy:`AUTOMATIC
    ~width:20
    ~packing:
    (fun w -> ignore (notebook#append_page
                        ~tab_label:(GMisc.label ~text:"Loading" ())#coerce w)) ()
    
    
let load_hbox = GPack.hbox 
  ~packing:load_nb#add_with_viewport ()

let load_image = GMisc.image
  ~packing:load_hbox#add ()
  
let load_frame = GBin.frame ~label:"Trimmings" ~packing:load_hbox#add ()
  
let load_bbox = GPack.button_box `VERTICAL
  ~spacing:20
  ~layout:`SPREAD
  ~packing:load_frame#add ()
  
  
  
(* Note Process *)
let proce_nb = 
  GBin.scrolled_window
    ~vpolicy:`AUTOMATIC
    ~hpolicy:`AUTOMATIC
    ~width:20
    ~packing:
    (fun w -> ignore (notebook#append_page
                        ~tab_label:(GMisc.label ~text:"Processing" ())#coerce w)) ()
    
let proce_hbox = GPack.hbox 
  ~packing:proce_nb#add_with_viewport ()
  
  
let proce_image = GMisc.image
  ~packing:proce_hbox#add ()
  
let proce_frame = GBin.frame ~label:"Trimmings" ~packing:proce_hbox#add ()
  
let proce_bbox = GPack.button_box `VERTICAL
  ~spacing:20
  ~layout:`SPREAD
  ~packing:(proce_frame#add) ()

  
(* Note Display *)
let disp_nb = 
  GBin.scrolled_window
    ~vpolicy:`AUTOMATIC
    ~hpolicy:`AUTOMATIC
    ~width:20
    ~packing:
    (fun w -> ignore (notebook#append_page
                        ~tab_label:(GMisc.label ~text:"3D Display" ())#coerce w)) ()
    
(* OpenGl *)
let hb = GPack.hbox ~packing:disp_nb#add_with_viewport ()
let table = GPack.table ~rows: 2 ~columns: 3 ~packing: hb#add ()

open GMain
open Graphics

let area = Graphics.getGlArea (table#attach ~left: 1 ~top: 0 ~expand: `BOTH) 600 400
let view = new view area

let obj1 = new Struct.triangle (0.0,5.0,0.0) (-5.0,-5.0,0.0) (5.0,-5.0,0.0) (1.0,0.0,0.0) (0.0,1.0,0.0) (0.0,0.0,1.0)
let obj2 = new Struct.triangle (0.0,20.0,-10.0) (-5.0,-5.0,1.0) (5.0,-5.0,1.0) (1.0,0.0,0.0) (0.0,1.0,0.0) (0.0,0.0,1.0)

let _ = view#add(obj1 :> render) ; view#add(obj2 :> render)

let scale ~orientation ~callback ~value ?packing () =
    let adjustment = GData.adjustment ~lower: 0.0 ~upper: 360.0 () in
    adjustment#connect#value_changed
      ~callback: (fun () -> callback adjustment#value);
    adjustment#set_value value;
    GRange.scale orientation ~adjustment ~draw_value: false ?packing ()

let sx = scale ~orientation: `VERTICAL ~callback: view#rotx  ~value: 40.0
      ~packing: (table#attach ~left: 2 ~top: 0 ~expand: `Y) ()
let sy = scale ~orientation: `HORIZONTAL ~callback: view#roty ~value: 20.0
      ~packing: (table#attach ~left: 1 ~top: 1 ~expand: `X) ()
let sz = scale ~orientation: `VERTICAL ~callback: view#rotz ~value: 10.0
      ~packing: (table#attach ~left: 0 ~top: 0 ~expand: `Y) ()

let _ = Timeout.add ~ms: 20 ~callback: view#idle
  
let create_box (r,g,b) h box =
  let h_entry_box = GPack.hbox ~spacing:30 ~packing:box#add () in
  let spin_box = GEdit.spin_button
    ~adjustment:(GData.adjustment 
                   ~value:h 
                   ~lower:0. 
                   ~upper:10000. 
                   ~page_size:0. ())
    ~digits:2
    ~packing:box#pack () in
  let _ = GButton.color_button
                   ~color:(GDraw.color (`RGB (r*256,g*256,b*256)))
                   ~packing:h_entry_box#pack () in
  spin_box

let rec create_box_rec h b= function
  |[] -> []
  |e::l when not(List.mem e (d#get_c)) -> (create_box e (500. -. h) b)::create_box_rec (h -. 25.) b l
  |_ -> []
    
    
    
let create_boxe (r,g,b) h box =
  let spin_box = GPack.hbox ~spacing:30 ~packing:box#add () in
  let spin_button = GEdit.spin_button
    ~adjustment:(GData.adjustment 
                   ~value:h 
                   ~lower:1. 
                   ~upper:999.
                   ~page_size:0. ())
    ~digits:0
    ~wrap:true
    ~packing:spin_box#pack () in
  let _ = GButton.color_button
    ~color:(GDraw.color (`RGB (r*256,g*256,b*256)))
    ~packing:spin_box#pack () in
  spin_button
    
    
let rec create_spin_rec h box = function
  |[] -> !spin
  |(r,g,b)::l when not (List.mem (r,g,b) d#get_c) ->  (create_boxe (r,g,b) h box)::create_spin_rec (h +. 25.) box l
  |_::l -> create_spin_rec h box l
    
    

let spin_maj bb l = 
  spin := create_spin_rec 0. bb l
    
let rec spin_merge = function
  |(_,[]) | ([],_)-> []
  |((s::l1),(r,g,b)::l2)-> (r,g,b,s#value_as_int)::spin_merge (l1,l2)

let rec spiny_comp (w,x,y,z) = function
  |[] -> false
  |(r,b,g,_)::l when (r==w && b==x && g==y) -> true
  |_::l -> spiny_comp (w,x,y,z) l

let rec spiny_merge = function
  |(l,[]) | ([],l) -> l
  |(e1::l1,l2) when not(spiny_comp e1 l2) -> e1::spiny_merge (l1,l2)
  |(e1::l1,l2) -> spiny_merge (l1,l2)
    
(* Buttons *)
    
let color_frame = GBin.frame ~label:"Height Color Association" ~packing:load_bbox#add ()

let color_bbox = GPack.button_box `VERTICAL
  ~packing:color_frame#add ()

let spin_frame = GBin.frame ~label:"Accuracy" ~packing:load_bbox#add ()
let spin_pas = GEdit.spin_button
  ~adjustment:(GData.adjustment 
                 ~value:10.
                 ~lower:0. 
                 ~upper:100. 
                 ~page_size:0. ())
  ~digits:0
  ~packing:spin_frame#add ()

let actual =
  let button = GButton.button
    ~label:"Update"
    ~packing:load_bbox#add () in
  ignore(button#connect#clicked ~callback:(fun _ ->
    load_image#set_file d#get_t;
    d#set_l_c (Image.get_color_areas d#get_t); (* Recording the color list*)
    spin_maj color_bbox (List.rev d#get_l_c); (* Creating the list of spins *)
    d#set_q (spiny_merge ((d#get_q),(spin_merge (!spin,d#get_l_c)))); (* Recording (r,g,b,h) *)
    d#set_c (d#get_l_c); (* Comparison to avoid duplication *)
  Image.write_str_color_areas d#get_q;
                                    ));
  button
  
let launch_cont =
  let button = GButton.button
    ~label:"Contour"
    ~packing:proce_bbox#add () in
  ignore (button#connect#clicked ~callback:(fun _ ->
    ignore(Image.detect_outlines d#get_t);
    ignore(proce_image#set_file ((d#get_t)^"_O"));
  ));
  button
    
let launch_cont =
  let button = GButton.button
    ~label:"Wire"
    ~packing:proce_bbox#add () in
  ignore (button#connect#clicked ~callback:(fun _ ->
    ignore(Image.draw_squared_grid d#get_t spin_pas#value_as_int);
                                            ignore(proce_image#set_file ((d#get_t)^"_G"));
  ));
  button

(*Main Window*)
    
(* "main" function*)
let run () =
  (*Show the Window*)
  window#connect#destroy ~callback:GMain.quit;
  ignore (window#show ());
  GMain.Main.main ();
  ()
    
